Skip to content

u-boot: v2026.01: fix BTRFS zstd decompression failure (error 70)#9651

Open
iav wants to merge 2 commits intoarmbian:mainfrom
iav:fix/uboot-btrfs-zstd-decompression
Open

u-boot: v2026.01: fix BTRFS zstd decompression failure (error 70)#9651
iav wants to merge 2 commits intoarmbian:mainfrom
iav:fix/uboot-btrfs-zstd-decompression

Conversation

@iav
Copy link
Copy Markdown
Contributor

@iav iav commented Apr 10, 2026

Summary

  • Fix zstd decompression in U-Boot when booting from a BTRFS partition with zstd compression
  • The generic zstd_decompress() wrapper in lib/zstd/zstd.c fails for BTRFS extents due to two sector-alignment mismatches
  • Call zstd_decompress_dctx() directly with zstd_find_frame_compressed_size() to strip input padding and ZSTD_getFrameContentSize() to handle output buffer size mismatch
  • Patch applies to both v2026.01 and v2025.10 (fs/btrfs/compression.c is identical)

Root cause

  1. Sector-aligned compressed size: BTRFS stores compressed extents padded to sector boundaries (4096 bytes). zstd_decompress_dctx() rejects trailing data after the zstd frame, breaking regular (non-inline) extents.

  2. Sector-aligned decompressed size: BTRFS compresses in sector-sized blocks, so the zstd frame content size may exceed ram_bytes from extent metadata (e.g. a 3906-byte file is compressed as a 4096-byte block). zstd_decompress_dctx() returns ZSTD_error_dstSize_tooSmall (error 70) for inline extents.

Symptoms:

zstd_decompress: failed to decompress: 70
BTRFS: An error occurred while reading file /boot/boot.scr

Testing done

  • Helios64 (RK3399), U-Boot v2026.01, SD card with BTRFS + zstd compression
  • Helios4 (Marvell A388), U-Boot v2025.10, BTRFS + zstd — boots successfully
  • boot.scr, armbianEnv.txt (inline extents) read successfully
  • Image (37MB), DTB (90KB), uInitrd (30MB) (regular compressed extents) read successfully
  • Kernel starts, system boots to login prompt

🤖 Assisted by Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed BTRFS zstd decompression handling for properly processing sector-aligned padding and oversized buffers in U-Boot v2025.10 and v2026.01, improving compatibility with compressed BTRFS filesystems.

@iav iav requested a review from prahal as a code owner April 10, 2026 21:32
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces Btrfs Zstd decompression to use libzstd dctx APIs: detect exact frame compressed/content sizes, strip sector padding, optionally allocate temp output and workspace, perform decompression with a zstd dctx, and return -1 on errors.

Changes

Cohort / File(s) Summary
BTRFS Zstd Decompression
fs/btrfs/compression.c, patch/u-boot/v2026.01/board_helios64/general-fix-btrfs-zstd-decompression.patch, patch/u-boot/v2025.10/board_helios4/general-fix-btrfs-zstd-decompression.patch, patch/u-boot/v2025.10/general-fix-btrfs-zstd-decompression.patch
Reworks static decompress_zstd() to call zstd_find_frame_compressed_size() to trim Btrfs sector padding, use ZSTD_getFrameContentSize() to size outputs, allocate temporary output if frame > requested dlen, allocate workspace via zstd_dctx_workspace_bound(), init dctx with zstd_init_dctx(), call zstd_decompress_dctx(), copy back dlen bytes when using a temp buffer, and return -1 on allocation or decompression errors.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant decompress_zstd
    participant Allocator
    participant libzstd
    Caller->>decompress_zstd: call(ibuf, clen, dbuf, dlen)
    decompress_zstd->>libzstd: zstd_find_frame_compressed_size(ibuf, clen)
    libzstd-->>decompress_zstd: frame_compressed_size / error
    decompress_zstd->>decompress_zstd: adjust clen (strip padding)
    decompress_zstd->>libzstd: ZSTD_getFrameContentSize(ibuf)
    libzstd-->>decompress_zstd: frame_decompressed_size
    alt frame_decompressed_size known and > dlen
        decompress_zstd->>Allocator: malloc(temp_out, frame_decompressed_size)
        Allocator-->>decompress_zstd: temp_out / NULL
    end
    decompress_zstd->>Allocator: malloc(workspace, zstd_dctx_workspace_bound())
    Allocator-->>decompress_zstd: workspace / NULL
    decompress_zstd->>libzstd: zstd_init_dctx(workspace)
    libzstd-->>decompress_zstd: dctx / error
    decompress_zstd->>libzstd: zstd_decompress_dctx(dctx, ibuf, clen, outbuf, outlen)
    libzstd-->>decompress_zstd: success / error
    alt success and temp_out used
        decompress_zstd->>Allocator: memcpy(dbuf, temp_out, dlen)
        decompress_zstd->>Allocator: free(temp_out)
    end
    decompress_zstd->>Allocator: free(workspace)
    decompress_zstd-->>Caller: return dlen or -1
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰
I sniffed the frame beneath the padded bed,
Pulled out its size, then gently spread,
A tiny workspace, dctx spun with care,
I hopped with bytes, half-copied to share,
Crunchy frames for supper — decompressed with flair!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly identifies the main fix: addressing BTRFS zstd decompression error 70 in U-Boot v2026.01, which aligns with the primary objective of the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added size/medium PR with more then 50 and less then 250 lines Needs review Seeking for review Hardware Hardware related like kernel, U-Boot, ... Patches Patches related to kernel, U-Boot, ... 05 Milestone: Second quarter release labels Apr 10, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
patch/u-boot/v2026.01/board_helios64/general-fix-btrfs-zstd-decompression.patch (1)

79-81: Consider size_t truncation on 32-bit platforms.

fcs is unsigned long long but malloc() takes size_t. On 32-bit systems where size_t is 32 bits, values > 4GB would truncate. While unlikely for BTRFS extents in practice (typical max extent size is 128MB), a defensive check could prevent unexpected behavior:

🛡️ Optional: Add size overflow check
 	if (fcs != ZSTD_CONTENTSIZE_ERROR &&
 	    fcs != ZSTD_CONTENTSIZE_UNKNOWN && fcs > dlen) {
+		if (fcs > SIZE_MAX)
+			return -1;
 		tmp = malloc(fcs);
 		if (!tmp)
 			return -1;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@patch/u-boot/v2026.01/board_helios64/general-fix-btrfs-zstd-decompression.patch`
around lines 79 - 81, The allocation uses malloc(tmp = malloc(fcs)) where fcs is
an unsigned long long and malloc takes size_t, so on 32-bit platforms fcs may
truncate; add a defensive size overflow check before calling malloc: verify fcs
<= (size_t)-1 (or SIZE_MAX) and fail fast (return -1) if it exceeds, then cast
fcs to size_t when calling malloc for tmp; reference symbols: fcs, tmp,
malloc().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@patch/u-boot/v2026.01/board_helios64/general-fix-btrfs-zstd-decompression.patch`:
- Around line 79-81: The allocation uses malloc(tmp = malloc(fcs)) where fcs is
an unsigned long long and malloc takes size_t, so on 32-bit platforms fcs may
truncate; add a defensive size overflow check before calling malloc: verify fcs
<= (size_t)-1 (or SIZE_MAX) and fail fast (return -1) if it exceeds, then cast
fcs to size_t when calling malloc for tmp; reference symbols: fcs, tmp,
malloc().

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 011b3518-0333-4433-a861-0fed3835b12a

📥 Commits

Reviewing files that changed from the base of the PR and between 4cd04e6 and 23601bd.

📒 Files selected for processing (1)
  • patch/u-boot/v2026.01/board_helios64/general-fix-btrfs-zstd-decompression.patch

@iav iav force-pushed the fix/uboot-btrfs-zstd-decompression branch from b4c330a to 2e91b75 Compare April 10, 2026 21:56
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@patch/u-boot/v2026.01/board_helios64/general-fix-btrfs-zstd-decompression.patch`:
- Around line 53-56: The out_len variable is declared as u32 which can truncate
64-bit frame sizes (fcs); change its type to size_t (e.g., replace "u32 out_len
= dlen;" with "size_t out_len = dlen;") and update any subsequent assignments
from fcs (e.g., when doing "out_len = fcs;") to use size_t (cast if necessary:
"out_len = (size_t)fcs;") so the decompression call receives the full 64-bit
capacity; ensure any other uses of out_len match size_t semantics.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 222d1f07-33d1-4207-b8e2-441e709bf5c9

📥 Commits

Reviewing files that changed from the base of the PR and between 23601bd and b4c330a.

📒 Files selected for processing (1)
  • patch/u-boot/v2026.01/board_helios64/general-fix-btrfs-zstd-decompression.patch

U-Boot's generic zstd_decompress() wrapper fails when used by BTRFS
due to two sector-alignment mismatches:

1. Compressed extents are stored padded to sector boundaries (4096),
   but zstd_decompress_dctx() rejects trailing data after the frame.

2. BTRFS compresses in sector-sized blocks, so the zstd frame content
   size may exceed ram_bytes. When the output buffer is sized to
   ram_bytes, zstd_decompress_dctx() returns dstSize_tooSmall (error 70).

Symptoms on zstd-compressed BTRFS partition:

  zstd_decompress: failed to decompress: 70
  BTRFS: An error occurred while reading file /boot/boot.scr

Fix by calling zstd_decompress_dctx() directly with:
- zstd_find_frame_compressed_size() to strip sector padding from input
- ZSTD_getFrameContentSize() to allocate a larger output buffer when
  the frame decompresses beyond the caller's buffer size

Tested on Helios64 (RK3399) booting from BTRFS+zstd SD card.
@iav iav force-pushed the fix/uboot-btrfs-zstd-decompression branch from 2e91b75 to c644580 Compare April 10, 2026 22:06
@iav iav added the Bugfix Pull request is fixing a bug label Apr 10, 2026
Same patch as v2026.01 — fs/btrfs/compression.c is identical.
Tested on Helios4 (Marvell A388).

Placed in both board_helios4/ (board-specific BOOTPATCHDIR) and
v2025.10/ root (shared, for boards like rockpi-e, orangepi4-lts).
@github-actions github-actions bot added size/large PR with 250 lines or more and removed size/medium PR with more then 50 and less then 250 lines labels Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

05 Milestone: Second quarter release Bugfix Pull request is fixing a bug Hardware Hardware related like kernel, U-Boot, ... Needs review Seeking for review Patches Patches related to kernel, U-Boot, ... size/large PR with 250 lines or more

Development

Successfully merging this pull request may close these issues.

1 participant